﻿// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Licensed under the Microsoft Public License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//  
// http://opensource.org/licenses/ms-pl
//  
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Microsoft.Samples.VisualStudio.SharePoint
{
    internal class WorkflowElementManifestParser
    {
        private XNamespace _ns = XNamespace.Get(@"http://schemas.microsoft.com/sharepoint/");
        private XDocument _document;
        private string _xamlFileName;

        private const string ListStartToken = "{$ListId:";
        private const string ListEndToken = ";}";

        private readonly Dictionary<string, string> _associationPropertiesMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                {"WSDisplayName", "DisplayName"},
                {"WSEventType", "EventType"},
                {"WSEnabled", "Enabled"},
                {"WSGUID","Id"},
                {"WSEventSourceGUID","EventSourceGUID"},
                {"HistoryListId","HistoryListId"},
                {"TaskListId","TaskListId"},
            };
        private readonly Dictionary<string, string> _definitionPropertiesMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                {"WSDescription","Description"},
                {"WSDisplayName","DisplayName"},
                {"RestrictToScope","RestrictAssociationToId"},
                {"RestrictToType","RestrictAssociationToType"},
                {"AssociationUrl","AssociationUrl"},
                {"InitiationUrl","InitiationUrl"},
            };

        private readonly HashSet<string> _listIdTokenReplaceFields = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        { 
            "TaskListId",
            "HistoryListId" ,
            "WSEventSourceGUID",
            "RestrictToScope"
        };

        public WorkflowElementManifestParser(XDocument elementManifest, string workflowXamlFileName)
        {
            _document = elementManifest;
            _xamlFileName = workflowXamlFileName;
        }

        public Dictionary<string, string> GetProperties()
        {
            return GetDefinitionProperties()
                .Concat(GetWorkflowAssociationItemAddedProperties())
                .Concat(GetWorkflowAssociationItemUpdatedProperties())
                .Concat(GetWorkflowAssociationWorkflowStartProperties())
                .ToDictionary(pair => pair.Key, pair => pair.Value);
        }

        public Dictionary<string, string> GetDefinitionProperties()
        {
            var definition = GetProperties(_xamlFileName, _definitionPropertiesMap, "WorkflowDefinition.");
            definition.Add("WorkflowDefinition.Id", Guid.NewGuid().ToString());

            if (definition.ContainsKey("WorkflowDefinition.RestrictAssociationToId"))
            {
                definition.Add("WorkflowAssociation.EventSourceGuid", definition["WorkflowDefinition.RestrictAssociationToId"]);
            }

            return definition;
        }

        public Dictionary<string, string> GetWorkflowAssociationWorkflowStartProperties()
        {
            return GetProperties("WorkflowStartAssociation", _associationPropertiesMap, "WorkflowAssociationManualStart.");
        }

        public Dictionary<string, string> GetWorkflowAssociationItemAddedProperties()
        {
            return GetProperties("ItemAddedAssociation", _associationPropertiesMap, "WorkflowAssociationItemAdded.");
        }

        public Dictionary<string, string> GetWorkflowAssociationItemUpdatedProperties()
        {
            return GetProperties("ItemUpdatedAssociation", _associationPropertiesMap, "WorkflowAssociationItemUpdated.");
        }

        private Dictionary<string, string> GetProperties(string fileName, Dictionary<string, string> propertyMap, string prefix)
        {
            var dictionary = ReadProperties(fileName);
            //create a new dictionary
            var newdictionary = dictionary
                .Where(pair => propertyMap.ContainsKey(pair.Key))
                .ToDictionary((pair) => string.Concat(prefix, propertyMap[pair.Key]), (pair) =>
                    {
                        if (_listIdTokenReplaceFields.Contains(pair.Key))
                            return pair.Value.Replace(ListStartToken, string.Empty).Replace(ListEndToken, string.Empty);
                        else
                            return pair.Value;
                    });

            return newdictionary;
        }

        private Dictionary<string, string> ReadProperties(string fileName)
        {
            // Get the XElement for the specified fileName
            var fileElement = _document.Root.Element(_ns + "Module").Elements(_ns + "File")
                .Where(file =>
                {
                    var url = file.Attribute("Url");
                    if (url == null)
                    {
                        return false;
                    }
                    return StringComparer.OrdinalIgnoreCase.Equals(url.Value, fileName);
                })
                .Select(file => file)
                .FirstOrDefault();

            if (fileElement == null)
            {
                return new Dictionary<string, string>();
            }

            var properties = from property in fileElement.Elements(_ns + "Property")
                             let Name = property.Attribute("Name")
                             let Value = property.Attribute("Value")
                             where Name != null && Value != null
                             select new { Name = Name.Value, Value = Value.Value };

            return properties.ToDictionary((obj) => obj.Name, (obj) => obj.Value);
        }
    }
}
